﻿using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using Newtonsoft.Json;
using OneWorks.Web.Common.BaiDu.Geocoding;
using OneWorks.Web.Common.BaiDu.Geoconv;
using OneWorks.Web.Common.BaiDu.Place;
using OneWorks.Web.Common.BaiDu.Translate;

namespace OneWorks.Web.Common.BaiDu
{
    public class BaiduLbs
    {
        private readonly string _key;

        public static string CurrentRequest = "";

        public BaiduLbs(string key)
        {
            _key = key;
        }

        /// <summary>
        /// 请求
        /// </summary>
        /// <param name="param"></param>
        /// <param name="baiduLbsType"></param>
        /// <param name="encoding"></param>
        /// <param name="action"></param>
        public void Request(string param, BaiduLbsType baiduLbsType, Encoding encoding, Action<string> action)
        {
            WebClient webClient = new WebClient { Encoding = encoding };
            string url = "";
            switch (baiduLbsType)
            {
                case BaiduLbsType.PlaceApIv2Search:
                    url = string.Format(BaiduConstParams.PlaceApIv2Search + "?{0}", param);
                    break;
                case BaiduLbsType.PlaceApIv2Detail:
                    url = string.Format(BaiduConstParams.PlaceApIv2Detail + "?{0}", param);
                    break;
                case BaiduLbsType.PlaceApIv2Eventsearch:
                    url = string.Format(BaiduConstParams.PlaceApIv2Eventsearch + "?{0}", param);
                    break;
                case BaiduLbsType.PlaceApIv2Eventdetail:
                    url = string.Format(BaiduConstParams.PlaceApIv2Eventdetail + "?{0}", param);
                    break;
                case BaiduLbsType.GeocodingApIv2:
                case BaiduLbsType.GeocodingApIv2Reverse:
                    url = string.Format(BaiduConstParams.GeocodingApIv2 + "?{0}", param);
                    break;
                case BaiduLbsType.Translate:
                    url = string.Format(BaiduConstParams.TranslateApi + "?{0}", param);
                    break;
                case BaiduLbsType.Geoconv:
                    url = string.Format(BaiduConstParams.GeoconvApi + "?{0}", param);
                    break;


            }
            CurrentRequest = url;
            action(webClient.DownloadString(url));
        }

        /// <summary>
        /// 响应
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="param"></param>
        /// <param name="baiduLbsType"></param>
        /// <param name="encoding"></param>
        public T Response<T>(string param, BaiduLbsType baiduLbsType, Encoding encoding)
        {
            T t = default(T);

            Request(param, baiduLbsType, encoding, json =>
                {
                    if (baiduLbsType == BaiduLbsType.GeocodingApIv2 || baiduLbsType == BaiduLbsType.GeocodingApIv2Reverse)
                    {
                        if (json.Contains("\"result\":[]"))
                        {
                            json = json.Replace("\"result\":[]", "\"result\":{}");
                        }
                    }
                    t = (T)JsonConvert.DeserializeObject(json, typeof(T));
                });
            return t;
        }

        public BaiduGeocodingResults BaiduGeocoding(string address, string city)
        {
            address = System.Web.HttpUtility.UrlEncode(address);
            city = System.Web.HttpUtility.UrlEncode(city);
            string request = string.Format("address={0}&output=json&ak={1}&city={2}", address, _key, city);
            var result = Response<BaiduGeocodingResults>(request, BaiduLbsType.GeocodingApIv2, Encoding.UTF8);
            if (result.Status == Status.Ok && result.Result.Location == null)
            {
                request = string.Format("address={0}&output=json&ak={1}&city={2}", city + address, _key, city);
                return Response<BaiduGeocodingResults>(request, BaiduLbsType.GeocodingApIv2, Encoding.UTF8);
            }
            return result;
        }

        public BaiduGeocodingResults BaiduGeocoding(string longitude, string dimensions, string pois)
        {
            var location = longitude + "," + dimensions;
            string request = string.Format("ak={0}&location={1}&pois={2}", _key, location, pois);
            return Response<BaiduGeocodingResults>(request, BaiduLbsType.GeocodingApIv2, Encoding.UTF8);
        }

        public BaiduPlaceResults BaiduPlace(BaiduPlaceParams placeParams, Func<BaiduPlaceParams, BaiduPlaceResults> func)
        {
            placeParams.Ak = _key;
            return func(placeParams);
        }

        public BaiduPlaceResults BaiduPlace(BaiduPlaceSearchParams placeParams)
        {
            return BaiduPlace(placeParams, results => Response<BaiduPlaceResults>(placeParams.ToString(), BaiduLbsType.PlaceApIv2Search, Encoding.UTF8));
        }

        public BaiduPlaceResults BaiduPlace(BaiduPlaceDetailParams placeParams)
        {
            return BaiduPlace(placeParams, results => Response<BaiduPlaceResults>(placeParams.ToString(), BaiduLbsType.PlaceApIv2Detail, Encoding.UTF8));
        }

        public BaiduPlaceResults BaiduPlace(BaiduPlaceEventSearchParams placeParams)
        {
            return BaiduPlace(placeParams, results => Response<BaiduPlaceResults>(placeParams.ToString(), BaiduLbsType.PlaceApIv2Eventsearch, Encoding.UTF8));
        }

        public BaiduPlaceResults BaiduPlace(BaiduPlaceEventDetailParams placeParams)
        {
            return BaiduPlace(placeParams, results => Response<BaiduPlaceResults>(placeParams.ToString(), BaiduLbsType.PlaceApIv2Eventdetail, Encoding.UTF8));
        }

        public TranslateResponse BaiduTranslate(TranslateRequest request)
        {
            request.ClientID = _key;
            return Response<TranslateResponse>(request.ToString(), BaiduLbsType.Translate, Encoding.UTF8);
        }

        public GeoconvResults BaiduGeoconv(GeoconvParams geoconvParams, ref List<GeoconvPOI> geoconvPois)
        {
            geoconvParams.Ak = _key;
            return Response<GeoconvResults>(geoconvParams.ToString(ref geoconvPois), BaiduLbsType.Geoconv, Encoding.UTF8);
        }

        public GeoconvResults BaiduGeoconv(GeoconvParams geoconvParams, GeoconvPOI geoconvPoi)
        {
            geoconvParams.Ak = _key;
            List<GeoconvPOI> geoconvPois = new List<GeoconvPOI>
                                               {
                                                   geoconvPoi
                                               };
            return Response<GeoconvResults>(geoconvParams.ToString(ref geoconvPois), BaiduLbsType.Geoconv, Encoding.UTF8);
        }
    }
}
